/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Rewriting;

import SPARQL.Constant;
import SPARQL.Obje;
import SPARQL.Pred;
import SPARQL.Subj;
import SPARQL.TriplePattern;
import SPARQL.Term;
import SPARQL.Variable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Mirko
 * 
 * 
 */
public class TripleUnifierEqualities extends TripleUnifier{
    
    /*
    Qui bisogna modificare il codice in modo tale che se gli atomi hanno alcune variabili uguali (a meno che non siano nella stessa regola) bisogna
    rinominare le variabili in modo tale che non ci sia questo clashing di variabili
    */
    
    
    private Map<Term,Term> unifierGraph;
    private boolean unification;
    private final TriplePattern tripleQuery;
    private final TriplePattern tripleMapping;
    
    public TripleUnifierEqualities(TriplePattern tripleQuery , TriplePattern tripleMapping){
        this.tripleQuery = tripleQuery;
        this.tripleMapping = tripleMapping;
        this.unifierGraph = new HashMap<Term, Term>();
        this.unification = false;
        computeUnifier();
    }
    
    public boolean unify(){
    return unification;
        
    }
    public Term maps(Term term1){
       
        return this.unifierGraph.get(term1);
         
    }
    
    public Term unifFunction(Term term){
        Term mappedTerm = term;
        Term iterationTerm = term;
        while (isMapped(iterationTerm)){
            mappedTerm = maps(iterationTerm);
            iterationTerm =  maps(iterationTerm);
            
        }
        return mappedTerm;
    }
    public boolean isMapped(Term term){
        return this.unifierGraph.containsKey(term);
    }
    
    private void insertMap(Term term1 , Term term2){
        this.unifierGraph.put(term1, term2);
    }

    private void computeUnifier() {
        
        boolean unify = false;
        //controlla le due triple, facendo differenza tra quella della query e quella del mapping. Quella della query e' a sinistra 
        if (this.tripleMapping!=null && this.tripleQuery != null){
            
            unify = true;
            
            
            
           
            
            //Comparing Subjects
            if (!this.tripleQuery.getS().equals(this.tripleMapping.getS())){
                if (unifFunction(this.tripleQuery.getS()) instanceof Constant && unifFunction(this.tripleMapping.getS()) instanceof Constant){

                    if (!unifFunction(this.tripleQuery.getS()).equals(unifFunction(this.tripleMapping.getS()))){
                        unify = false;
                    return;
                    }

                    }
                else{
                    if (unifFunction(this.tripleQuery.getS()) instanceof Variable && unifFunction(this.tripleMapping.getS()) instanceof Constant){

                    
                    unify = false;
                    return;
                    }
                    
                    if (unifFunction(this.tripleQuery.getS()) instanceof Variable){
                        
                        
                        if (!isMapped(this.tripleQuery.getS()))
                        this.insertMap(this.tripleQuery.getS(), this.tripleMapping.getS());
                        else 
                            insertMap(unifFunction(this.tripleQuery.getS()) , this.tripleMapping.getS());
                    }

                    else {
                       if (!isMapped(this.tripleMapping.getS()))
                        this.insertMap(this.tripleMapping.getS(), this.tripleQuery.getS());
                        else 
                            insertMap(unifFunction(this.tripleMapping.getS()) , this.tripleQuery.getS());
                    }
                }
            }
            //Comparing Predicates
            if (!this.tripleQuery.getP().equals(this.tripleMapping.getP())){
                if (unifFunction(this.tripleQuery.getP()) instanceof Constant && unifFunction(this.tripleMapping.getP()) instanceof Constant){

                    if (!unifFunction(this.tripleQuery.getP()).equals(unifFunction(this.tripleMapping.getP()))){
                        unify = false;
                    return;
                    }

                    }
                else{
                    if (unifFunction(this.tripleQuery.getP()) instanceof Variable && unifFunction(this.tripleMapping.getP()) instanceof Constant){

                    
                    unify = false;
                    return;
                    }
                    
                    if (unifFunction(this.tripleQuery.getP()) instanceof Variable){
                        
                        
                        if (!isMapped(this.tripleQuery.getP()))
                        this.insertMap(this.tripleQuery.getP(), this.tripleMapping.getP());
                        else 
                            insertMap(unifFunction(this.tripleQuery.getP()) , this.tripleMapping.getP());
                    }

                    else {
                       if (!isMapped(this.tripleMapping.getP()))
                        this.insertMap(this.tripleMapping.getP(), this.tripleQuery.getP());
                        else 
                            insertMap(unifFunction(this.tripleMapping.getP()) , this.tripleQuery.getP());
                    }
                }
            }
            //Comparing Objects
           if (!this.tripleQuery.getO().equals(this.tripleMapping.getO())){
                if (unifFunction(this.tripleQuery.getO()) instanceof Constant && unifFunction(this.tripleMapping.getO()) instanceof Constant){

                    if (!unifFunction(this.tripleQuery.getO()).equals(unifFunction(this.tripleMapping.getO()))){
                        unify = false;
                    return;
                    }

                    }
                else{
                    if (unifFunction(this.tripleQuery.getO()) instanceof Variable && unifFunction(this.tripleMapping.getO()) instanceof Constant){

                    
                    unify = false;
                    return;
                    }
                    
                    if (unifFunction(this.tripleQuery.getO()) instanceof Variable){
                        
                        
                        if (!isMapped(this.tripleQuery.getO()))
                        this.insertMap(this.tripleQuery.getO(), this.tripleMapping.getO());
                        else 
                            insertMap(unifFunction(this.tripleQuery.getO()) , this.tripleMapping.getO());
                    }

                    else {
                       if (!isMapped(this.tripleMapping.getO()))
                        this.insertMap(this.tripleMapping.getO(), this.tripleQuery.getO());
                        else 
                            insertMap(unifFunction(this.tripleMapping.getO()) , this.tripleQuery.getO());
                    }
                }
            }
            
            
                
            
            
            
        }
        
        this.unification = unify;
    }
    
    
    
    
   
}
        
